#!/usr/bin/env python
# check-incremental - Check if incremental compilation works -*- python -*-
#
# This source file is part of the Swift.org open source project
#
# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
# Licensed under Apache License v2.0 with Runtime Library Exception
#
# See http://swift.org/LICENSE.txt for license information
# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
#
# ----------------------------------------------------------------------------
#
# This is a wrapper for the swift compiler.
# It invokes the compiler multiple times and checks if the output object file
# is only written a single time.
# The main purpose of the check is to ensure that the compiler is
# deterministic.
#
# ----------------------------------------------------------------------------

import os
import subprocess
import sys


def main():
    verbose = False
    num_iterations = 4

    write_obj_file = False
    next_arg_is_output = False
    compare_time = True
    output_file = None

    for arg in sys.argv:
        if next_arg_is_output:
            output_file = arg
            next_arg_is_output = False
        elif arg == '-c':
            write_obj_file = True
        elif arg == '-disable-incremental-llvm-codegen':
            compare_time = False
        elif arg == '-o':
            next_arg_is_output = True

    if not write_obj_file or output_file is None:
        return

    new_args = sys.argv[1:]
    subprocess.check_call(new_args)

    if verbose:
        print "Reference compilation of " + output_file + ":"

    reference_md5 = subprocess.check_output(["md5", "-q", output_file])
    reference_time = os.path.getmtime(output_file)

    if verbose:
        print "  time = {}".format(reference_time)
        print "  md5 = " + reference_md5

    subprocess.check_call(["cp", output_file, output_file + ".ref.o"])

    for iteration in range(0, num_iterations):

        if verbose:
            print "Iteration {}:".format(iteration)

        subprocess.check_call(new_args)

        second_md5 = subprocess.check_output(["md5", "-q", output_file])
        second_time = os.path.getmtime(output_file)

        if verbose:
            print "  time = {}".format(second_time)
            print "  md5 = " + second_md5

        # This is the most important check: is the output file exactly the
        # same.
        if reference_md5 != second_md5:
            sys.exit("non-determinism when generating: " + output_file)

        # This is the bonus check: does the compiler not re-write the output
        # file. (For compilations < 1sec this check may succeed even if the
        # file was overwritten).
        if compare_time and reference_time != second_time:
            sys.exit("file re-written: " + output_file)


main()
